﻿--MacaroonXP, a World of Warcraft® user interface addon.
--Copyright© 2008 Connor H. Chenoweth, aka Maul

Macaroon.XPBars = {}
Macaroon.XPStatusbars = {}

MacaroonXPSavedState = {}

local find = string.find
local format = string.format
local gsub = string.gsub
local lower = string.lower
local sort = table.sort

local currentVersion = 30000.11
local xpFrameData = {}
local playerEnteredWorld, load, clickedBar, ss = false

local factionData = {
	repNameIndex = {},
	repFactionIndex = {},
	repDropDownIndex = {},
}

local repColors = {
	[0] = { l="a_Unknown", r=0.5, g=0.5, b=0.5, a=1.0 },
	[1] = { l="b_Hated", r=0.6, g=0.1, b=0.1, a=1.0 },
	[2] = { l="c_Hostile", r=0.7, g=0.2, b=0.2, a=1.0 },
	[3] = { l="d_Unfriendly", r=0.75, g=0.27, b=0, a=1.0 },
	[4] = { l="e_Neutral", r=0.9, g=0.7, b=0, a=1.0 },
	[5] = { l="f_Friendly", r=0.3, g=0.7, b=0.2, a=1.0 },
	[6] = { l="g_Honored", r=0.1, g=0.5, b=0.20, a=1.0 },
	[7] = { l="h_Revered", r=0.0, g=0.39, b=0.88, a=1.0 },
	[8] = { l="i_Exalted", r=0.58, g=0.0, b=0.55, a=1.0 },
}

local onEnter = {
	[1] = 2,
	[2] = 1,
	[3] = 1,
	[4] = 5,
	[5] = 4,
}

local barTextures = {
	[1] = { "Default", "Interface\\TargetingFrame\\BarFill2" },
	[2] = { "Contrast", "Interface\\AddOns\\Macaroon\\Images\\BarFill_contrast" },
	-- Following textures by Tonedef of WoWInterface
	[3] = { "Carpaint", "Interface\\AddOns\\Macaroon\\Images\\BarFill_Carpaint" },
	[4] = { "Gel", "Interface\\AddOns\\Macaroon\\Images\\BarFill_Gel" },
	[5] = { "Glassed", "Interface\\AddOns\\Macaroon\\Images\\BarFill_Glassed" },
	[6] = { "Soft", "Interface\\AddOns\\Macaroon\\Images\\BarFill_Soft" },
	[7] = { "Velvet", "Interface\\AddOns\\Macaroon\\Images\\BarFill_Velvet" },
}

local barBorders = {
	[1] = { "Tooltip", "Interface\\Tooltips\\UI-Tooltip-Border", 2, 2, 3, 3, 12, 12, -2, 3, 2, -3 },
	[2] = { "Slider", "Interface\\Buttons\\UI-SliderBar-Border", 3, 3, 6, 6, 8, 8 , -1, 5, 1, -5 },
	[3] = { "Dialog", "Interface\\AddOns\\Macaroon\\Images\\Border_Dialog", 11, 12, 12, 11, 26, 26, -7, 7, 7, -7 },
	[4] = { "None", "", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
}

local toggleOptions = {

}


local copyTable = Macaroon.copyTable
local clearTable = Macaroon.clearTable
local getChildrenAndRegions = Macaroon.getChildrenAndRegions
local MACAROON_STRINGS = MACAROON_STRINGS

local function xpBar_Update(self)

	self.statusbartext:SetText(xpFrameData[self.id][self.config.textIndex])

	if (self.textcolor) then
		self.statusbartext:SetTextColor(self.textcolor[1], self.textcolor[2], self.textcolor[3])
	end

	if (self.bordercolor) then
		self.statusbarborder:SetBackdropBorderColor(self.bordercolor[1], self.bordercolor[2], self.bordercolor[3])
	end

	if (self.config.textIndex < 4) then
		if (self.restedXP ~= nil) then
			if (self.restcolor) then
				self.statusbar:SetStatusBarColor(self.restcolor[1], self.restcolor[2], self.restcolor[3], 1.0)
			else

			end
		else
			if (self.norestcolor) then
				self.statusbar:SetStatusBarColor(self.norestcolor[1], self.norestcolor[2], self.norestcolor[3], 1.0)
			else

			end
		end

		if (self.nextXP) then
			self.statusbar:SetMinMaxValues(0, self.nextXP)
		end

		if (self.currXP) then
			self.statusbar:SetValue(self.currXP)
		end
	else
		self.statusbar:SetStatusBarColor(repColors[self.standingID].r, repColors[self.standingID].g, repColors[self.standingID].b, repColors[self.standingID].a)

		if (self.repMax) then
			self.statusbar:SetMinMaxValues(0, self.repMax)
		end
		if (self.repCurr) then
			self.statusbar:SetValue(self.repCurr)
		end
	end
end

local function updateXPRep(self, event, ...)

	if (not playerEnteredWorld) then
		return
	end

	for i=1,5 do
		xpFrameData[self.id][i] = ""
	end

	if (event == "PLAYER_XP_UPDATE" or "UPDATE_EXHAUSTION" or "PLAYER_ENTERING_WORLD") then

		local currXP = UnitXP("player")
		local nextXP = UnitXPMax("player")
		local restedXP = GetXPExhaustion()
		local percentXP, restedLevels, bubbles

		percentXP = (currXP/nextXP)*100
		restedLevels = GetXPExhaustion()
		bubbles = currXP/(nextXP/20)

		bubbles = gsub(bubbles,"(%d*)(%.)(%d*)","%1")

		if (restedXP ~= nil) then
			restedLevels = restedLevels/nextXP
			restedLevels = gsub(restedLevels,"(%d*)(%.)(%d%d)(%d*)","%1%2%3")
			xpFrameData[self.id][3] = restedXP.." - "..restedLevels..MACAROONXP_STRINGS.RESTED
		else
			xpFrameData[self.id][3] = MACAROONXP_STRINGS.NORESTED
		end

		percentXP = format("%.1f", percentXP)

		xpFrameData[self.id][1] = currXP.."/"..nextXP.." - "..bubbles..MACAROONXP_STRINGS.BUBBLES
		xpFrameData[self.id][2] = percentXP.."%"

		self.nextXP = nextXP
		self.currXP = currXP
		self.restedXP = restedXP
	end

	if (event == "UPDATE_FACTION" or "CHAT_MSG_COMBAT_FACTION_CHANGE") then

		local name, hex, standing, standingID, barMin, barMax, barValue, isHeader
		local repLevel = "Unknown"
		local index = 1

		if (GetNumFactions() > 0) then

			if (not factionData.repNameIndex[self.id]) then
				factionData.repNameIndex[self.id] = {}
			else
				clearTable(factionData.repNameIndex[self.id])
			end

			if (not factionData.repFactionIndex[self.id]) then
				factionData.repFactionIndex[self.id] = {}
			else
				clearTable(factionData.repFactionIndex[self.id])
			end

			if (not factionData.repDropDownIndex[self.id]) then
				factionData.repDropDownIndex[self.id] = {}
			else
				clearTable(factionData.repDropDownIndex[self.id])
			end

			for i=1, GetNumFactions() do

				if (not IsFactionInactive(i)) then

					name, _, standingID, barMin, barMax, barValue, _, _, isHeader, _, _ = GetFactionInfo(i)

					if (isHeader == nil) then

						hex = format("%02x%02x%02x", repColors[standingID].r*255, repColors[standingID].g*255, repColors[standingID].b*255)

						factionData.repNameIndex[self.id][index] = repColors[standingID].l..i.."|"..name

						factionData.repFactionIndex[self.id][index] = repColors[standingID].l..i
						factionData.repDropDownIndex[self.id][index] = repColors[standingID].l..i.."|cff"..hex..name.." - "..math.floor(((barValue-barMin)/(barMax-barMin))*100).."%|r"

						if (self.config.repMonitor == 0 and name) then
							self.config.repMonitor = i
							self.config.repSelect = i
						end

						index = index + 1
					end

					if (self.config.repSelect == -1) then
						if (...) then
							if (find(..., name)) then
								self.config.repMonitor = i
							end
						end
					else
						if (self.config.repSelect ~= 0) then
							self.config.repMonitor = self.config.repSelect
						end
					end
				end
			end

			sort(factionData.repNameIndex[self.id])
			sort(factionData.repFactionIndex[self.id])
			sort(factionData.repDropDownIndex[self.id])

			for k,v in pairs(factionData.repNameIndex[self.id]) do
				factionData.repNameIndex[self.id][k] = gsub(v, "^[^|]+", "")
				factionData.repNameIndex[self.id][k] = gsub(factionData.repNameIndex[self.id][k], "^%|+", "")
			end

			if (self.config.repMonitor) then

				for k,v in pairs(factionData.repFactionIndex[self.id]) do
					if (tonumber(self.config.repMonitor) == tonumber(string.match(v, "%d+"))) then
						index = k
					end
				end

				if (index) then

					for i=1, GetNumFactions() do
						if (not IsFactionInactive(i)) then
							name, _, standingID, barMin, barMax, barValue, _, _, isHeader, _, _ = GetFactionInfo(i)
							if (name == factionData.repNameIndex[self.id][index]) then
								break
							end
						end
					end

					if (factionData.repNameIndex[self.id][index]) then

						standing = gsub(repColors[standingID].l, "^%a%p", "")

						xpFrameData[self.id][4] = factionData.repNameIndex[self.id][index].." - "..standing.." ("..math.floor(((barValue-barMin)/(barMax-barMin))*100).."%)"
						xpFrameData[self.id][5] = factionData.repNameIndex[self.id][index].." - "..(barValue-barMin).."/"..(barMax-barMin)
						self.repMax = barMax-barMin
						self.repCurr = barValue-barMin
						self.standingID = standingID
						self.repLevel = repColors[standingID].l

					end
				end
			end
		end
	end

	xpBar_Update(self)
end

local function setBorder(statusbar)

	local border = getglobal(statusbar.statusbar:GetName().."Border")
	local background = getglobal(statusbar.statusbar:GetName().."Background")

	border:SetBackdrop( { bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
				edgeFile = barBorders[statusbar.config.border][2],
				tile = true,
				tileSize = barBorders[statusbar.config.border][7],
				edgeSize = barBorders[statusbar.config.border][8],
				insets = { left = barBorders[statusbar.config.border][3],
					   right = barBorders[statusbar.config.border][4],
					   top = barBorders[statusbar.config.border][5],
					   bottom = barBorders[statusbar.config.border][6]
					 }
				} )

	border:SetPoint("TOPLEFT", barBorders[statusbar.config.border][9], barBorders[statusbar.config.border][10])
	border:SetPoint("BOTTOMRIGHT", barBorders[statusbar.config.border][11], barBorders[statusbar.config.border][12])

	border:SetBackdropColor(0, 0, 0, 0)
	border:SetBackdropBorderColor(statusbar.bordercolor[1], statusbar.bordercolor[2], statusbar.bordercolor[3], 1)
	border:SetFrameLevel(statusbar.statusbar:GetFrameLevel()+1)

	background:SetBackdropColor(0, 0, 0, 1)
	background:SetBackdropBorderColor(0, 0, 0, 0)
	background:SetFrameLevel(0)
end

local function updateStatusBarData(statusbar, bar, state)

	statusbar.bar = bar
	statusbar.alpha = bar.config.alpha
	statusbar.showGrid = bar.config.showGrid
	statusbar:SetAttribute("showgrid-bar", bar.config.showGrid)
	statusbar.config.showstates = state
	statusbar:SetAttribute("showstates", state)

	statusbar:SetWidth(statusbar.config.width)
	statusbar:SetHeight(statusbar.config.height)

	statusbar.statusbar:SetOrientation(bar.config.visuals.orientation)

	statusbar.textcolor = bar.config.visuals.color1
	statusbar.bordercolor = bar.config.visuals.color2
	statusbar.restcolor = bar.config.visuals.color3
	statusbar.norestcolor = bar.config.visuals.color4

	setBorder(statusbar)

	statusbar.config.bar = bar:GetID()
	statusbar.config.stored = false

	statusbar:SetFrameStrata(bar.config.buttonStrata)
	statusbar:SetFrameLevel(4)

	xpBar_Update(statusbar)

	if (bar.handler) then
		Macaroon.UpdateButtonVisibility(statusbar, bar.handler:GetAttribute("state-current"))
	end

	statusbar.editframetype:SetText("")

	Macaroon.EditFrames[statusbar] = statusbar.editframe
end

local function updateWidth(editframe, statusbar, delta)

	local modifier = math.ceil(editframe.elapsed/0.5)

	if (modifier <= 0) then
		modifier = 1
	end

	if (delta > 0 ) then
		statusbar.config.width = statusbar.config.width + 0.5 * modifier
	else
		statusbar.config.width = statusbar.config.width - 0.5 * modifier
		if (statusbar.config.width < 10) then
			statusbar.config.width = 10
		end
	end

	statusbar.bar.updateBar(statusbar.bar, nil, true, true)

end

local function updateHeight(editframe, statusbar, delta)

	local modifier = math.ceil(editframe.elapsed/0.5)

	if (modifier <= 0) then
		modifier = 1
	end

	if (delta > 0 ) then
		statusbar.config.height = statusbar.config.height + 0.5 * modifier
	else
		statusbar.config.height = statusbar.config.height - 0.5 * modifier
		if (statusbar.config.height < 4) then
			statusbar.config.height = 4
		end
	end

	statusbar.bar.updateBar(statusbar.bar, nil, true, true)
end

local function updateTexture(editframe, statusbar, delta)

	local index = statusbar.config.texture

	if (delta > 0) then

		if (index == 1) then
			index = #barTextures
		else
			index = index - 1
		end

		statusbar.config.texture = index

	else

		if (index == #barTextures) then
			index = 1
		else
			index = index + 1
		end

		statusbar.config.texture = index
	end

	statusbar.statusbar:SetStatusBarTexture(barTextures[index][2])
end

local function updateBorder(editframe, statusbar, delta)

	local index = statusbar.config.border

	if (delta > 0) then

		if (index == 1) then
			index = #barBorders
		else
			index = index - 1
		end

		statusbar.config.border = index

	else

		if (index == #barBorders) then
			index = 1
		else
			index = index + 1
		end

		statusbar.config.border = index
	end

	setBorder(statusbar)
end

local actionTable = {
	[MACAROONXP_STRINGS.XPBAR_EDIT_BUTTON_1] = updateWidth,
	[MACAROONXP_STRINGS.XPBAR_EDIT_BUTTON_2] = updateHeight,
	[MACAROONXP_STRINGS.XPBAR_EDIT_BUTTON_3] = updateTexture,
	[MACAROONXP_STRINGS.XPBAR_EDIT_BUTTON_4] = updateBorder,
}

local function updateValues(self, delta)

	if (actionTable[self.action]) then
		actionTable[self.action](self, self:GetParent(), delta)
	end
end


local function statusbarDefaults(index, statusbar)

	statusbar.config = {
		type = "statusbar",
		bar = 0,
		barPos = 0,
		showstates = "",
		laststate = "",
		scale = 1,
		XOffset = 0,
		YOffset = 0,
		textIndex = 1,
		repSelect = 0,
		repMonitor= 0,
		width = 200,
		height = 12,
		texture = 1,
		border = 1,
	}
end

local function createStatusBar(index)

	local statusbar

	if (_G["MacaroonXPStatusBar"..index]) then
		statusbar = _G["MacaroonXPStatusBar"..index]
	else
		statusbar = CreateFrame("Button", "MacaroonXPStatusBar"..index, UIParent, "MacaroonXPRepBarTemplate")
	end

	local statusbarName = statusbar:GetName()
	local objects = getChildrenAndRegions(statusbar)

	for k,v in pairs(objects) do
		local name = gsub(v, statusbar:GetName(), "")
		statusbar[lower(name)] = _G[v]
	end

	statusbar:SetID(index)
	statusbar.id = index

	statusbar.click = false
	statusbar.standingID = 0
	statusbar.xpmark = {}
	statusbar.lastText = 1
	xpFrameData[statusbar.id] = {}

	statusbarDefaults(index, statusbar)

	objects = getChildrenAndRegions(statusbar)

	for k,v in pairs(objects) do
		local name = gsub(v, statusbar:GetName(), "")
		statusbar[lower(name)] = _G[v]
	end

	statusbar.updateButtonData = updateStatusBarData
	statusbar.editframe.updateValues = updateValues

	statusbar:SetAttribute("showgrid", 0)
	statusbar:SetAttribute("showstates", "")
	statusbar:SetAttribute("hotkeys", "")
	statusbar:SetAttribute("hasaction", true)
	statusbar:SetAttribute("_childupdate", [[

			self:SetAttribute("stateshown", false)

			for showstate in gmatch(self:GetAttribute("showstates"), "[^;]+") do
				if (message and strfind(message, showstate)) then
					if (self:GetAttribute("hasaction") or self:GetAttribute("showgrid-bar") or self:GetAttribute("editmode")) then
						self:Show()
					end
					self:SetAttribute("stateshown", true)
				end
			end

			if (not self:GetAttribute("stateshown")) then
				self:Hide()
			end
		]] )


	if (not ss.xpstatusbars) then ss.xpstatusbars = {} end

	ss.xpstatusbars[index] = { statusbar.config }

	Macaroon.XPStatusbars[index] = { statusbar, 1 }

	updateXPRep(statusbar, "PLAYER_XP_UPDATE", nil)
	updateXPRep(statusbar, "UPDATE_FACTION", nil)

	return statusbar
end

function Macaroon.XPBar_OnLoad(self)

	self:RegisterEvent("PLAYER_XP_UPDATE")
	self:RegisterEvent("UPDATE_EXHAUSTION")
	self:RegisterEvent("UPDATE_FACTION")
	self:RegisterEvent("CHAT_MSG_COMBAT_FACTION_CHANGE")
	self:RegisterEvent("PLAYER_ENTERING_WORLD")
	self:RegisterForClicks("AnyUp")

	--local texture
	--for i=1,19 do
	--	texture = self.statusbar:CreateTexture(self.statusbar:GetName().."Mark"..i, "OVERLAY", "MacaroonXPMarker")
	--	texture:SetPoint("TOPLEFT", (self:GetWidth()/19*i), 1)
	--	texture:SetPoint("BOTTOMLEFT", (self:GetWidth()/19*i), -1)
	--	self.xpmark[i] = texture
	--end
end

function Macaroon.XPBar_OnEvent(self, event, ...)
	updateXPRep(self, event, ...)
end

function Macaroon.XPBar_OnEnter(self)

	self.lastText = self.config.textIndex

	self.config.textIndex = onEnter[self.config.textIndex] or 1

	xpBar_Update(self)
end

function Macaroon.XPBar_OnLeave(self)

	if (not self.click) then
		self.config.textIndex = self.lastText or 1
	end

	self.click = false

	xpBar_Update(self)
end

function Macaroon.XPBar_OnClick(self, button, down)

	clickedBar = self

	if (button == "RightButton") then

		if (DropDownList1:IsVisible()) then
			DropDownList1:Hide()
		else
			Macaroon.XPRepDropDown_OnLoad(self.dropdown)
			updateXPRep(self, "UPDATE_FACTION", nil)
			ToggleDropDownMenu(1, nil, self.dropdown, self, 0, 0)
			DropDownList1:ClearAllPoints()
			DropDownList1:SetPoint("LEFT", self, "RIGHT", 3, 0)
			DropDownList1:SetClampedToScreen(true)
			PlaySound("igMainMenuOptionCheckBoxOn")
		end
	else

		self.config.textIndex = self.config.textIndex + 1

		if ( self.config.textIndex > #xpFrameData[self.id]) then
			self.config.textIndex = 1
		end

		xpBar_Update(self)

		self.click = true
	end
end

function Macaroon.XPRepDropDown_OnLoad(self)

	if (clickedBar) then

		if (clickedBar.config.repSelect == 0) then
			clickedBar.config.repSelect = clickedBar.config.repMonitor
		end

		UIDropDownMenu_Initialize(self, Macaroon.XPRepDropDown_Initialize, "MENU")
	end
end

function Macaroon.XPRepDropDown_Initialize()

	if (clickedBar) then

		local info = UIDropDownMenu_CreateInfo()
		local checked, repLine, repIndex

		info.text = "Auto Select"
		info.func = function(self) clickedBar.config.repSelect = self.value updateXPRep(clickedBar, "UPDATE_FACTION") end
		if (clickedBar.config.repSelect == -1) then
			checked = 1
		else
			checked = nil
		end
		info.value = -1
		info.checked = checked
		UIDropDownMenu_AddButton(info)

		for i=1,#factionData.repDropDownIndex[clickedBar.id] do

			repIndex = tonumber(string.match(factionData.repFactionIndex[clickedBar.id][i], "%d+"))
			repLine = gsub(factionData.repDropDownIndex[clickedBar.id][i], "^[^|]+", "")

			info.text = repLine
			info.func = function(self) clickedBar.config.repSelect = self.value if (clickedBar.config.textIndex < 4) then clickedBar.config.textIndex = 4 end updateXPRep(clickedBar, "UPDATE_FACTION") end

			if (repIndex == clickedBar.config.repSelect) then
				checked = 1
			else
				checked = nil
			end
			info.value = repIndex
			info.checked = checked
			UIDropDownMenu_AddButton(info)
		end
	end
end

local uniqueBarDefaults = {

	columns = 1,
	padH = 5,
	padV = 6,
	visuals = {
		dimensions = { 200, 12 },
		orientation = "HORIZONTAL",
		color1 = { 1, 0.82, 0 },
		color2 = { 0.8, 0.8, 0.8 },
		color3 = { 0, 0.39, 0.88 },
		color4 = { 0.58, 0, 0.55 },
	},
}

function Macaroon.XPBarDefaults(bar)

	for k,v in pairs(uniqueBarDefaults) do

		if (type(v) == "table") then
			bar.config[k] = copyTable(v)
		else
			bar.config[k] = v
		end
	end

	bar.config.name = "XP/Rep Bar "..bar:GetID()

	bar.handler:SetAttribute("state-current", bar.config.currentstate)
	bar.handler:SetAttribute("state-last", bar.config.laststate)
end

local function updateVariables(element, defaultConfig)

	-- Add new vars
	for key,value in pairs(defaultConfig) do

		if (element.config[key] == nil) then

			if (element.config[lower(key)] ~= nil) then

				element.config[key] = element.config[lower(key)]
				element.config[lower(key)] = nil
			else
				element.config[key] = value
			end
		end
	end
	-- Add new vars

	-- Kill old vars
	for key,value in pairs(element.config) do
		if (defaultConfig[key] == nil) then
			element.config[key] = nil
		end
	end
	-- Kill old vars
end

function Macaroon.XPLoadSavedData(saved, profile)

	if (saved) then

		local savedState = copyTable(saved)
		local newBar, defaultConfig = false

		if (savedState.xpbars) then

			clearTable(Macaroon.XPBars)

			defaultConfig = Macaroon.GetBarDefaults()

			for k,v in pairs(savedState.xpbars) do

				local bar = Macaroon.CreateBar("xp", true, true)

				bar.config = copyTable(savedState.xpbars[k][1])

				updateVariables(bar, defaultConfig)

				bar.handler:SetAttribute("state-current", bar.config.currentstate)

				bar.handler:SetAttribute("state-last", bar.config.laststate)

			end

			savedState.xpbars = nil

		elseif (not profile) then

			newBar = Macaroon.CreateBar("xp", true, true)
		end

		if (savedState.xpstatusbars) then

			for k,v in pairs(Macaroon.XPStatusbars) do
				Macaroon.StoreButton(v[1], Macaroon.XPStatusbars)
			end

			defaultConfig = Macaroon.GetXPStatusbarDefaults()

			for k,v in pairs(savedState.xpstatusbars) do

				local statusbar = createStatusBar(k)

				statusbar.config = copyTable(savedState.xpstatusbars[k][1])

				updateVariables(statusbar, defaultConfig)
			end

			savedState.xpstatusbars = nil

		elseif (not profile) then

			createStatusBar(1)
		end

		if (newBar) then
			Macaroon.AddButton(1, newBar)
		end

		if (newBar) then
			Macaroon.Ypos = Macaroon.UpdateBarPositions(Macaroon.XPBars, true, Macaroon.Ypos)
		end

		for k,v in pairs(savedState) do
			if (ss[k]) then
				ss[k] = v
			end
		end

		load = true
	end
end

function Macaroon.XPUpdateElements()

	for k,v in pairs(Macaroon.XPBars) do

		v.stateschanged = true

		v.statusbarCountChanged = true

		v.updateBar(v, true, true, true, true)
	end

	for k,v in pairs(Macaroon.XPBars) do

		v.updateBarLink(v)
	end
end

function Macaroon.XPSaveCurrentState()

	if (load) then

		if (ss.xpbars) then
			clearTable(ss.xpbars)
		else
			ss.xpbars = {}
		end

		for k,v in pairs(Macaroon.XPBars) do
			ss.xpbars[k] = { v.config }
		end

		if (ss.xpstatusbars) then
			clearTable(ss.xpstatusbars)
		else
			ss.xpstatusbars = {}
		end

		for k,v in pairs(Macaroon.XPStatusbars) do
			ss.xpstatusbars[k] = { v[1].config }
		end

		ss.savedVersion = currentVersion
	end

	return ss, "xpbars", "xpstatusbars"
end

function Macaroon.GetXPStatusbarDefaults()

	local defaults = {}

	statusbarDefaults(0, defaults)

	return defaults.config
end

function Macaroon.AddXPStatusBar(bar)

	local index, made, statusbar = 1, false

	while not made do

		if (not _G[bar.btnType..index]) then
			statusbar = createStatusBar(index)
			made = true
		end

		index = index + 1
	end

	return statusbar
end

function Macaroon.XPEditor_OnClick(self, action)

	PlaySound("gsTitleOptionOK")

	local editframe = Macaroon.CurrentButton.editframe

	if (action) then

		editframe.message:SetText(MACAROONXP_STRINGS["XPBAR_EDIT_BUTTON_"..self:GetID()])

		editframe.hover = true

		editframe.action = action
	end

	MacaroonButtonEditor.shrink = true
end

function Macaroon.XPEditorCheck_OnClick(self, action)

	PlaySound("gsTitleOptionOK")

	local statusbar, checked, option = Macaroon.CurrentButton, self:GetChecked()

	for k,v in pairs(toggleOptions) do
		if (v == action) then
			option = k
		end
	end

	if (statusbar) then

		if (checked) then
			statusbar.config[option] = true
		else
			statusbar.config[option] = false
		end
	end
end

function Macaroon.XPEditor_OnLoad(self)

	local breakIndex, xOffset, index, frame, lastFrame, anchorFrame, lastButton = 1, 5, 1

	index = 1

	while (MACAROONXP_STRINGS["XPBAR_EDIT_BUTTON_"..breakIndex]) do
		breakIndex = breakIndex + 1
	end

	local yOffset = (self:GetHeight()-((breakIndex+1)*17))/breakIndex+1

	while (MACAROONXP_STRINGS["XPBAR_EDIT_BUTTON_"..index]) do

		frame = CreateFrame("Button", "$parentButton"..index, self, "MacaroonButtonTemplate2")
		frame:SetID(index)
		frame:SetWidth(90)
		frame:SetHeight(20)
		frame:SetScript("OnClick", function(self, button) Macaroon.XPEditor_OnClick(self, self.action) end)
		frame.text = _G[frame:GetName().."Text"]
		frame.text:SetText(MACAROONXP_STRINGS["XPBAR_EDIT_BUTTON_"..index])
		frame.action = frame.text:GetText()

		if (index == 1 or index == breakIndex) then
			if (anchorFrame) then
				frame:SetPoint("TOPLEFT", anchorFrame, "TOPRIGHT", 2, 0)
				anchorFrame = frame
				breakIndex = breakIndex + (breakIndex - 1)
			else
				frame:SetPoint("TOPLEFT", self, "TOPLEFT", xOffset, -5)
				anchorFrame = frame
			end
			lastFrame = frame
		else
			frame:SetPoint("TOP", lastFrame, "BOTTOM", 0, -(yOffset))
			lastFrame = frame
		end

		lastButton = frame

		index = index + 1
	end

	breakIndex = 1

	while (MACAROONXP_STRINGS["XPBAR_CHECK_"..breakIndex]) do
		breakIndex = breakIndex + 1
	end

	yOffset = (self:GetHeight()-((breakIndex+1)*20))/breakIndex+1

	xOffset, index, frame, lastFrame, anchorFrame, iOffset = -123, 1, nil, nil, nil, 0

	while (MACAROONXP_STRINGS["XPBAR_CHECK_"..index]) do

		frame = CreateFrame("CheckButton", "$parentCheck"..index-iOffset, self, "MacaroonOptionCBTemplate")
		frame:SetID(index-iOffset)
		frame:SetScript("OnClick", function(self, button) Macaroon.XPEditorCheck_OnClick(self, self.action) end)
		frame:SetScript("OnShow", function(self) end)
		frame.text = _G[frame:GetName().."Text"]
		frame.text:SetText(MACAROONXP_STRINGS["XPBAR_CHECK_"..index])
		frame.action = frame.text:GetText()

		if (index == 1 or index == breakIndex) then
			if (anchorFrame) then
				frame:SetPoint("TOPLEFT", anchorFrame, "TOPRIGHT", 2, 0)
				anchorFrame = frame
				breakIndex = breakIndex + (breakIndex - 1)
			else
				frame:SetPoint("TOPRIGHT", self, "TOPRIGHT", xOffset, -25)
				anchorFrame = frame
			end
			lastFrame = frame
		else
			frame:SetPoint("TOP", lastFrame, "BOTTOM", 0, -(yOffset))
			lastFrame = frame
		end

		index = index + 1
	end

	Macaroon.ButtonEdit_AddPanel(self, "statusbar")

	self:Hide()
end

function Macaroon.XPEditor_OnShow(self)

	local statusbar, index, frame = Macaroon.CurrentButton, 1

	if (statusbar) then

		while (_G["MacaroonButtonEditorXPEditCheck"..index]) do

			frame = _G["MacaroonButtonEditorXPEditCheck"..index]

			for k,v in pairs(toggleOptions) do
				if (v == frame.action) then
					if (statusbar.config[k]) then
						frame:SetChecked(1)
					else
						frame:SetChecked(nil)
					end
				end
			end

			index = index + 1
		end

		statusbar.action = nil
	end
end

function Macaroon.XPSetSaved()

	if (MacaroonSavedState.useShared and MacaroonSharedSavedState[MacaroonSavedState.sharedProfile]) then
		ss = MacaroonSharedSavedState[MacaroonSavedState.sharedProfile]

		if (not ss) then
			ss = MacaroonXPSavedState
		end
	else
		ss = MacaroonXPSavedState
	end

	return ss
end

local function controlOnEvent(self, event, ...)

	if (event == "VARIABLES_LOADED") then

		Macaroon.XPSetSaved()

		Macaroon.CreateBarTypes.xp = { "XPbars", ss, Macaroon.XPBars, Macaroon.XPStatusbars, "MacaroonXPStatusBar", Macaroon.AddXPStatusBar, Macaroon.XPBarDefaults, "2XP/Rep Bar" }

		Macaroon.StatesToSave.xp = Macaroon.XPSaveCurrentState
		Macaroon.SavedDataLoad.xp = Macaroon.XPLoadSavedData
		Macaroon.SavedDataUpdate.xp = Macaroon.XPUpdateElements
		Macaroon.SetSavedVars.xp = Macaroon.XPSetSaved

	elseif (event == "PLAYER_LOGIN") then

		Macaroon.XPLoadSavedData(ss)

	elseif (event == "PLAYER_ENTERING_WORLD" and not playerEnteredWorld) then

		Macaroon.XPUpdateElements()

		playerEnteredWorld = true
	end
end

local frame = CreateFrame("Frame", nil, UIParent)
frame:SetScript("OnEvent", controlOnEvent)
frame:RegisterEvent("VARIABLES_LOADED")
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("PLAYER_ENTERING_WORLD")